import { v4 as uuid4 } from 'uuid';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import {
  CallHandler,
  ExecutionContext,
  HttpStatus,
  Injectable,
  Logger,
  NestInterceptor,
} from '@nestjs/common';

import { env } from '../settings';

const requestHeaderName = 'X-Request-Id';

@Injectable()
export class AppInterceptor implements NestInterceptor {
  // 全局的请求处理
  private readonly logger = new Logger(AppInterceptor.name);

  private convertCreatedToOK(statusCode: number) {
    if (statusCode === HttpStatus.CREATED) {
      return HttpStatus.OK;
    }
    return statusCode;
  }

  private getClientIp(req: any) {
    return (
      req.headers['x-forwarded-for'] ||
      req.headers['x-real-ip'] ||
      req.socket.remoteAddress ||
      req.ip
    );
  }

  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const startTime = performance.now();

    const req = context.switchToHttp().getRequest();
    const reqIp = this.getClientIp(req);
    const requestId = req.get(requestHeaderName) || uuid4();

    this.logger.log(`Request start: ${req.method} ${req.url}`, [
      AppInterceptor.name,
      { ip: reqIp, requestId: requestId },
    ]);
    req['requestId'] = requestId;

    return next.handle().pipe(
      map((data) => {
        const est = performance.now() - startTime;
        const res = context.switchToHttp().getResponse();
        this.logger.log(`Finish on: ${est} ms`, [
          AppInterceptor.name,
          { requestId: requestId },
        ]);

        res.status(this.convertCreatedToOK(res.statusCode));
        res.header('X-Version', env.VERSION);
        res.header('X-Response-Time', `${est} ms`);
        res.header(requestHeaderName, requestId);

        return data;
      }),
    );
  }
}
